/**
 * Anderground project - Subway maps processor application.
 * Copyright (C) 2008-2009 Eldar Abusalimov, Ilya Shurigyn
 * 
 * This file is part of Anderground.
 * 
 * Anderground is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * Anderground is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Anderground.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.anderground.modules.drawer.dynamic;

import static org.anderground.modules.drawer.dynamic.Config.stationLightRadius;
import static org.anderground.modules.drawer.dynamic.Config.transferWidth;
import static org.anderground.modules.drawer.dynamic.Config.tunnelWidth;

import java.util.ArrayList;

import org.anderground.core.graphics.Canvas;
import org.anderground.core.graphics.Color;
import org.anderground.core.graphics.LinearGradient;
import org.anderground.core.graphics.Paint;
import org.anderground.core.graphics.Path;
import org.anderground.core.graphics.PathDashPathEffect;
import org.anderground.core.graphics.PathEffect;
import org.anderground.core.graphics.PointF;
import org.anderground.core.model.Transfer;
import org.anderground.core.model.Tunnel;
import org.anderground.internal.graphics.abstaractions.AbstractPaint.Style;

/**
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 * 
 */
abstract class Bacillus {

	/**
	 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
	 * 
	 */
	protected class TunnelPart {

		public boolean opposite = false;

		public boolean singleSide = true;

		public int color;

		public Tunnel tunnel;

	}

	/**
	 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
	 * 
	 */
	protected class TransferPart {

		public boolean opposite = false;

		public Transfer transfer;

	}

	protected CompoundBacillus compoundBacillus;

	protected Amoeba evenAmoeba, oddAmoeba;

	protected ArrayList<TransferPart> transferParts = new ArrayList<TransferPart>();

	protected ArrayList<TunnelPart> tunnelParts = new ArrayList<TunnelPart>();

	protected int tunnelsSize = 0, transfersSize = 0;

	private static Paint tunnelPaint = new Paint();

	private static Paint singleTunnelPaint = new Paint();

	private static Paint wayPaint = new Paint();

	private static Paint wayBackPaint = new Paint();

	private static Paint transferPaint = new Paint();

	private static int[] gradientColors = new int[] { Color.DKGRAY,
			Color.WHITE, Color.WHITE, Color.DKGRAY };

	private static float[] gradientPositions = new float[] { 0, (float) 0.4,
			(float) 0.6, 1 };

	private static Path smallPath;

	private static Path bigPath;

	private static PathEffect smallEffect;

	private static PathEffect bigEffect;

	private static PointF offset = new PointF();

	protected void draw(Canvas canvas) {
		PointF evenPointF = this.evenAmoeba.pointF;
		PointF oddPointF = this.oddAmoeba.pointF;
		PointF normal = PointF.difference(evenPointF, oddPointF);
		normal.rotateCW();
		normal.normalize();

		if (transferParts.isEmpty()) {
			normal.scale(tunnelWidth);
			offset.set(normal);
			offset.scale((float) (1 - tunnelsSize) / 2);
			for (TunnelPart tunnelPart : tunnelParts) {
				tunnelPaint.setColor(tunnelPart.color);
				canvas.drawLine(evenPointF.x + offset.x, evenPointF.y
						+ offset.y, oddPointF.x + offset.x, oddPointF.y
						+ offset.y, tunnelPaint);

				if (tunnelPart.singleSide) {
					if (tunnelPart.opposite) {
						canvas.drawLine(oddPointF.x + offset.x, oddPointF.y
								+ offset.y, evenPointF.x + offset.x,
								evenPointF.y + offset.y, singleTunnelPaint);
					} else {
						canvas.drawLine(evenPointF.x + offset.x, evenPointF.y
								+ offset.y, oddPointF.x + offset.x, oddPointF.y
								+ offset.y, singleTunnelPaint);
					}
				}
				offset.add(normal);

			}
		} else {
			normal.scale(transferWidth / 2);
			float x = evenPointF.x;
			float y = evenPointF.y;
			float dx = normal.x;
			float dy = normal.y;

			transferPaint.setShader(new LinearGradient(x - dx, y - dy, x + dx,
					y + dy, gradientColors, gradientPositions));
			canvas.drawLine(evenPointF, oddPointF, transferPaint);
		}
	}

	protected void highlight(Canvas canvas, int highlightColor) {
		canvas.drawLine(this.evenAmoeba.pointF, this.oddAmoeba.pointF,
				wayBackPaint);
		canvas
				.drawLine(this.evenAmoeba.pointF, this.oddAmoeba.pointF,
						wayPaint);
		draw(canvas);
	}

	public static void setup() {
		singleTunnelPaint.setStrokeWidth(transferWidth);
		tunnelPaint.setStrokeWidth(tunnelWidth);
		transferPaint.setStrokeWidth(transferWidth);
	}

	static {
		smallPath = new Path();
		bigPath = new Path();

		float pos = tunnelWidth / 2;
		smallPath.moveTo(0, pos);
		smallPath.lineTo(pos, pos);
		smallPath.lineTo(0, -pos);
		smallPath.lineTo(-pos, -pos);

		pos = tunnelWidth;
		bigPath.moveTo(0, 2 * pos);
		bigPath.lineTo(pos, 2 * pos);
		bigPath.lineTo(0, -2 * pos);
		bigPath.lineTo(-pos, -2 * pos);

		smallEffect = new PathDashPathEffect(smallPath, tunnelWidth, 0,
				PathDashPathEffect.Style.ROTATE);
		bigEffect = new PathDashPathEffect(bigPath, 10, 2,
				PathDashPathEffect.Style.ROTATE);

		wayPaint.setColor(Color.argb(127, 255, 0, 0));
		wayPaint.setAntiAlias(true);
		wayPaint.setStrokeWidth(stationLightRadius);
		wayPaint.setPathEffect(bigEffect);
		wayPaint.setStrokeCap(Paint.Cap.ROUND);

		wayBackPaint.setAntiAlias(true);
		wayBackPaint.setStrokeCap(Paint.Cap.ROUND);
		wayBackPaint.setStrokeWidth(stationLightRadius);
		wayBackPaint.setColor(Color.argb(180, 255, 224, 0));

		singleTunnelPaint.setColor(Color.argb(215, 255, 255, 255));
		singleTunnelPaint.setAntiAlias(true);
		singleTunnelPaint.setStrokeWidth(tunnelWidth);
		singleTunnelPaint.setPathEffect(smallEffect);
		singleTunnelPaint.setStrokeCap(Paint.Cap.ROUND);

		tunnelPaint.setAntiAlias(true);
		tunnelPaint.setStrokeCap(Paint.Cap.ROUND);

		transferPaint.setAntiAlias(true);
		transferPaint.setStrokeCap(Paint.Cap.BUTT);
		transferPaint.setStyle(Style.FILL_AND_STROKE);
		transferPaint.setColor(Config.DEFAULT_COLOR);

	}

}
